package org.example.sys.security;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.security.Keys;
import org.example.core.Constants;
import org.example.core.utils.JSONUtil;

import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;

/**
 * JWT工具类
 * @author Calvin
 */
public class JwtUtil {

    /**
     * 获取请求中的access_token
     *
     * @param request HttpServletRequest
     * @return String
     */
    public static String getAccessToken(HttpServletRequest request) {
        String accessToken = ServletUtil.getHeaderIgnoreCase(request, Constants.TOKEN_HEADER_NAME);
        if (StrUtil.isNotBlank(accessToken)) {
            if (accessToken.startsWith(Constants.TOKEN_TYPE)) {
                accessToken = StrUtil.removePrefix(accessToken, Constants.TOKEN_TYPE).trim();
            }
        } else {
            accessToken = request.getParameter(Constants.TOKEN_PARAM_NAME);
        }
        return accessToken;
    }

    /**
     * 生成token
     *
     * @param subject          载体
     * @param expire           过期时间
     * @param base64EncodedKey base64编码的Key
     * @return token
     */
    public static String buildToken(JwtSubject subject, Long expire, String base64EncodedKey) {
        return buildToken(JSONUtil.toJSONString(subject), expire, decodeKey(base64EncodedKey));
    }

    /**
     * 生成token
     *
     * @param subject 载体
     * @param expire  过期时间
     * @param key     密钥
     * @return token
     */
    public static String buildToken(String subject, Long expire, Key key) {
        Date expireDate = new Date(System.currentTimeMillis() + 1000 * expire);
        return Jwts.builder()
                .setSubject(subject)
                .setExpiration(expireDate)
                .setIssuedAt(new Date())
                .signWith(key)
                .compact();
    }

    /**
     * 解析token
     *
     * @param token            token
     * @param base64EncodedKey base64编码的Key
     * @return Claims
     */
    public static Claims parseToken(String token, String base64EncodedKey) {
        return parseToken(token, decodeKey(base64EncodedKey));
    }

    /**
     * 解析token
     *
     * @param token token
     * @param key   密钥
     * @return Claims
     */
    public static Claims parseToken(String token, Key key) {
        return Jwts.parser()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 获取JwtSubject
     *
     * @param claims Claims
     * @return JwtSubject
     */
    public static JwtSubject getJwtSubject(Claims claims) {
        return JSONUtil.parseObject(claims.getSubject(), JwtSubject.class);
    }

    /**
     * 生成Key
     *
     * @return Key
     */
    public static Key randomKey() {
        return Keys.secretKeyFor(SignatureAlgorithm.HS256);
    }

    /**
     * base64编码key
     *
     * @return String
     */
    public static String encodeKey(Key key) {
        return Encoders.BASE64.encode(key.getEncoded());
    }

    /**
     * base64编码Key
     *
     * @param base64EncodedKey base64编码的key
     * @return Key
     */
    public static Key decodeKey(String base64EncodedKey) {
        if (StrUtil.isBlank(base64EncodedKey)) {
            return null;
        }
        return Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64EncodedKey));
    }

    public static String encodeKey(String key) {
        return Encoders.BASE64.encode(key.getBytes(StandardCharsets.UTF_8));
    }



    //验证jwt是否合法，即解密
    public static Claims parseJWT(String jsonWebToken, String base64Security) {
        try {
            return Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(base64Security))
                    .parseClaimsJws(jsonWebToken).getBody();
        } catch (Exception e) {
            return null;
        }
    }

    // 创建jwt,即加密
    public static String createJWT(String subject, String base64Security, long ttlMillis) {
        Date now = new Date();
        // 生成签名密钥
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, SignatureAlgorithm.HS256.getJcaName());
        // 添加构成JWT的参数
        JwtBuilder builder = Jwts.builder().setSubject(subject).setIssuedAt(now)
                .signWith(SignatureAlgorithm.HS256, signingKey);

        // 添加Token过期时间
        if (ttlMillis >= 0) {
            Date exp = new Date(System.currentTimeMillis() + ttlMillis);
            builder.setExpiration(exp);
        }
        // 生成JWT
        return builder.compact();
    }




    public static void main1(String[] args) {

        String getTokenKey = encodeKey("heating-manage");
        System.out.println("getTokenKey:" + getTokenKey);

        String base64EncodedKey ="ULgNsWJ8rPjRtnjzX/Gv2RGS80Ksnm/ZaLpvIL+NrBg=";
        Key key = decodeKey(base64EncodedKey);
        System.out.println("key:" + JSON.toJSONString(key.getEncoded()));
        String username = "calvin";
        Long tokenExpireTime = 60 * 60 * 24L;
        int tokenRefreshTime = 30;
        String accessToken = buildToken(new JwtSubject(username), tokenExpireTime, getTokenKey);
        System.out.println("accessToken:" + accessToken);

        Claims claims = JwtUtil.parseToken(accessToken, getTokenKey);
        JwtSubject jwtSubject = JwtUtil.getJwtSubject(claims);
        System.out.println("jwtSubject:" + JSONUtil.toJSONString(jwtSubject));
    }

        public static void main(String[] args) {
            String base64Security = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY=";
            String subject = "calvin";
            long ttlMillis = 3600000; // 1小时

            // 生成JWT token
            String token = createJWT(subject, base64Security, ttlMillis);
            System.out.println("Generated token: " + token);

            // 解析JWT token
            Claims claims = parseJWT(token, base64Security);
            if (claims!= null) {
                System.out.println("Subject: " + claims.getSubject());
            } else {
                System.out.println("Token is invalid or expired.");
            }
        }

}
